﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WarehouseManagement.BusinessLogic.DTO;
using WarehouseManagement.DataAccess;

namespace WarehouseManagement.BusinessLogic.BC
{
    public class DebitBC : BaseBC
    {

        private decimal GetSupplierDebt(int supplierId, DateTime fromDate)
        {
            var list = Context.BoughtMerchandiseDebits.AsEnumerable()
                .Where(e =>
                    e.FromDate.Date <= fromDate
                     && e.SupplierId == supplierId)
                .ToList();
            if (list.Count > 0)
            {
                list = list.OrderByDescending(e => e.FromDate.Date)
                    .ToList();
                return list.FirstOrDefault().Debt;
            }
            else
            {
                return 0;
            }
        }

        //// Nợ đầu kỳ
        //private decimal GetSupplierLastPeriodDebt(int supplierId, string documentNumber, DateTime t)
        //{
        //    var lastMonth = new DateTime(t.Year, t.Month, 1).AddDays(-1);
        //    var lastMonthDebt = GetSupplierDebt(supplierId, lastMonth);

        //    var poBC = new POBC();
        //    // Get giá trị hàng đã đặt
        //    var paid = GetPOPayment(supplierId, new DateTime(t.Year, t.Month, 1), t.Date.AddDays(-1));

        //    // Get giá trị hàng đã nhận
        //    var received = GetReceivedMerchandiseValue(supplierId, new DateTime(t.Year, t.Month, 1), t.Date.AddDays(-1));

        //    // Giá trị phiếu thu
        //    var receiptValue = this.GetReceiptsValueOf(documentNumber, new DateTime(t.Year, t.Month, 1), t.Date.AddDays(-1));

        //    return lastMonthDebt + (paid - received) - receiptValue;
        //}

        //// Nợ cuối kỳ
        //public decimal ComputeAndSaveSupplierDebt(int supplierId, string documentNumber, DateTime fromDate, DateTime toDate)
        //{
        //    // Get Nợ đầu kỳ
        //    var lastPeriodDebt = GetSupplierLastPeriodDebt(supplierId, documentNumber, fromDate);

        //    // Get giá trị hàng đã đặt
        //    var paid = GetPOPayment(supplierId, fromDate.Date, toDate.Date);

        //    // Get giá trị hàng đã nhận
        //    var received = GetReceivedMerchandiseValue(supplierId, fromDate.Date, toDate.Date);

        //    // Get giá trị phiếu thu
        //    var receiptValue = this.GetReceiptsValueOf(documentNumber, fromDate.Date, toDate.Date);

        //    // Nợ cuối kỳ = Nợ đầu kỳ + đã đặt - đã nhận - đã thu
        //    var endPeriodDebt = lastPeriodDebt + (paid - received) - receiptValue;
        //    SaveDebt(supplierId, toDate, endPeriodDebt);
        //    return endPeriodDebt;
        //}

        // Đã trả
        private decimal GetPOPayment(int supplierId, DateTime fromDate, DateTime toDate)
        {
            var list = Context.POs.Where(
                e => (e.SupplierId == supplierId)
                && (e.PODate.Date >= fromDate.Date && e.PODate.Date <= toDate.Date));
            if (list.Count() > 0)
            {
                return list.Sum(e => e.PODetails.Sum(f => (decimal)f.UnitPriceAfterTax * (decimal)f.Quantity * e.ExchangeRate));
            }
            return 0;
        }

        // Đã nhận
        private decimal GetReceivedMerchandiseValue(int supplierId, DateTime fromDate, DateTime toDate)
        {
            var list = Context.Imports.Where(e => e.SupplierId == supplierId
                && (e.CreatedDate.Date >= fromDate.Date && e.CreatedDate.Date <= toDate.Date));
            if (list.Count() > 0)
            {
                return list.Sum(e => e.ImportDetails.Sum(f => (decimal)f.Quantity * (decimal)f.UnitPriceAfterTax.Value * e.ExchangeRate));
            }
            return 0;
        }

        // //Document number: số chứng từ
        // //Get giá trị phiếu thu
        //private decimal GetReceiptValue(string documentNumber, DateTime fromDate, DateTime toDate)
        //{
        //    var list = Context.Receipts.Where(e => e.DocumentNumber == documentNumber
        //        && (e.Date.Date >= fromDate.Date && e.Date.Date <= toDate.Date));
        //    if (list.Count() > 0)
        //    {
        //        return list.Sum(e => e.Value);
        //    }
        //    return 0;

        //}


        //private void SaveDebt(int supplierId, DateTime fromDate, decimal debt)
        //{
        //    //var lastItem = GetSupplierDebt(supplierId, fromDate);
        //    //if (lastItem == debt)
        //    //    return;
        //    var obj = Context.BoughtMerchandiseDebits.SingleOrDefault(e => e.SupplierId == supplierId && e.FromDate.Date == fromDate.Date);
        //    if (obj != null)
        //    {
        //        obj.Debt = debt;
        //    }
        //    else
        //    {
        //        obj = new DataAccess.BoughtMerchandiseDebit()
        //        {
        //            Id = Guid.NewGuid(),
        //            Debt = debt,
        //            FromDate = fromDate,
        //            SupplierId = supplierId
        //        };
        //        Context.BoughtMerchandiseDebits.InsertOnSubmit(obj);
        //    }
        //    SubmitChanges();
        //}



        //===================================================================================================
        private IEnumerable<MerchandiseDebitDTO> GetMerchandiseDebitInfo(int supplierId, DateTime fromDate, DateTime toDate)
        {
            var list = new List<MerchandiseDebitDTO>();
            var obj = GetLastPeriodDebitInfo(supplierId, fromDate, toDate);
            if (obj != null && obj.RemainDebt != 0)
                list.Add(obj);

            list.AddRange(GetPODebitInfo(supplierId, fromDate, toDate));
            return list.ToList();
        }

        public IEnumerable<MerchandiseDebitDTO> GetMerchandiseDebitInfo(DateTime fromDate, DateTime toDate)
        {
            var suppliers = Context.Suppliers.AsEnumerable();
            var list = new List<MerchandiseDebitDTO>();
            foreach (var item in suppliers)
            {
                list.AddRange(GetMerchandiseDebitInfo(item.Id, fromDate.Date, toDate.Date));
            }
            return list;
        }

        private MerchandiseDebitDTO GetLastPeriodDebitInfo(int supplierId, DateTime fromDate, DateTime toDate)
        {

            //var list = Context.BoughtMerchandiseDebits.Where(e => e.SupplierId == supplierId
            //    && (e.FromDate.Date >= fromDate.Date && e.FromDate.Date <= toDate.Date));

            //BoughtMerchandiseDebit item = null;
            //if (list.Count() > 0)
            //{
            //    item = list.OrderByDescending(e => e.FromDate).FirstOrDefault();
            //}

            //if (item == null)
            //{
            //    return null;
            //}

            var item = GetLastPeriodDebtOfSupplier(supplierId, toDate.Date);
            if (item == null) return null;

            var poBC = new POBC();
            var currencyBC = new CurrencyBC();

            var obj = new MerchandiseDebitDTO()
            {
                Date = item.FromDate,
                Debt = item.Debt,
                DocumentNumber = item.DocumentNumber,
                Notes = "(Nợ đầu kỳ)",
                CurrencyName = "VND",
                ExchangeRate = 1,
                CurrencyId = currencyBC.GetCurrencyByCode("VND").CurrencyId,
                Paid = poBC.GetTotalReceivedMoney(item.DocumentNumber, fromDate, toDate, item.FromDate),
                PartnerId = item.SupplierId,
                PartnerName = item.Supplier.SupplierName,
                IsPO = false

            };

            poBC = null;
            currencyBC = null;

            return obj;

        }

        private IEnumerable<MerchandiseDebitDTO> GetPODebitInfo(int supplierId, DateTime fromDate, DateTime toDate)
        {
            var list = Context.POs.Where(e => e.SupplierId == supplierId
                && (e.PODate.Date >= fromDate.Date && e.PODate.Date <= toDate.Date))
                .ToList();

            var poBC = new POBC();

            var list2 = new List<MerchandiseDebitDTO>();
            foreach (var e in list)
            {
                var dto = new MerchandiseDebitDTO()
                 {
                     Date = e.PODate,
                     Debt = poBC.GetTotalPOCost(e.Id),
                     CurrencyName = e.Currency.CurrencyCode,
                     ExchangeRate = e.ExchangeRate,
                     DocumentNumber = e.PONumber,
                     Notes = e.Notes,
                     Paid = poBC.GetTotalReceivedMoney(e.PONumber, fromDate.Date, toDate.Date, e.PODate),
                     PartnerId = e.SupplierId,
                     PartnerName = e.Supplier.SupplierName,
                     CurrencyId = e.CurrencyId,
                     IsPO = true,
                 };
                if (dto.RemainDebt == 0) continue;
                dto.DetailsInfomation = new System.Collections.ArrayList();
                foreach (var d in e.PODetails)
                {
                    dto.DetailsInfomation.Add(ConvertToChildItem(d));
                }
                list2.Add(dto);

            }
            return list2;



        }

        //public void ComputeDebitsForNextMonth()
        //{
        //    DateTime fromDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
        //    DateTime toDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month));
        //    var list = GetMerchandiseDebitInfo(fromDate, toDate).ToList();
        //    var list2 = list.GroupBy(e => e.PartnerId)
        //        .Select(e => new
        //        {
        //            SupplierId = e.Key,
        //            Debt = e.Sum(f => f.Debt)
        //        });

        //    var debtList = Context.BoughtMerchandiseDebits.ToList();
        //    foreach (var item in debtList)
        //    {
        //        var oldMonth = item.FromDate.Month;
        //        var oldYear = item.FromDate.Year;
        //        if (oldMonth != DateTime.Today.Month && oldYear != DateTime.Today.Year)
        //        {
        //            var debtItem = list2.SingleOrDefault(e => e.SupplierId == item.SupplierId);
        //            SaveDebt(item.SupplierId, DateTime.Now, debtItem.Debt);
        //        }
        //    }

        //}
        private object ConvertToChildItem(PODetail detail)
        {
            return new
            {
                MerchandiseName = detail.Merchandise.MerchandiseName,
                Unit = detail.Merchandise.Unit,
                Quantity = detail.Quantity,
                UnitPrice = detail.UnitPrice,
                Tax = detail.Tax,
                ShippingFee = detail.ShippingFee,
                UnitPriceAfterTax = detail.UnitPriceAfterTax,
                TotalUnitPrice = (decimal)detail.UnitPriceAfterTax * (decimal)detail.Quantity * detail.PO.ExchangeRate
            };
        }
        //private decimal GetPOTotalValue(Guid poId)
        //{
        //    var list = Context.PODetails.Where(e => e.POId == poId);
        //    if (list.Count() > 0)
        //    {
        //        // Chưa tính xong đâu...
        //        return list.Sum(e => (decimal)e.Quantity * (decimal)e.UnitPriceAfterTax * e.PO.ExchangeRate);
        //    }
        //    return 0;

        //}

        //private decimal GetReceivedMoneyOfPO(Guid poId)
        //{
        //    GetReceiptsValueOf(
        //}


        public BoughtMerchandiseDebit GetLastPeriodDebtOfSupplier(int supplierId, DateTime untilDate)
        {
            var obj = Context.BoughtMerchandiseDebits.Where(e => e.SupplierId == supplierId
                && e.FromDate.Date <= untilDate.Date);
            if (obj.Count() > 0)
                obj = obj.OrderByDescending(e => e.FromDate);

            var rsl = obj.FirstOrDefault();

            return rsl;
        }

        public IEnumerable<SupplierAndDebtDTO> GetSupplierAndDebtList()
        {
            var suppliers = Context.Suppliers.ToList();
            foreach (var sup in suppliers)
            {
                var obj = GetLastPeriodDebtOfSupplier(sup.Id, DateTime.Today);
                var debt = 0m;
                if (obj != null)
                {
                    debt = obj.Debt;
                }
                yield return new SupplierAndDebtDTO
                {
                    SupplierId = sup.Id,
                    SupplierName = sup.SupplierName,
                    Debt = debt,
                    Notes = "(Nợ đầu kỳ)"
                };
            }
        }

        private void UpdateSupplierDebt(int supplierId, decimal debt)
        {
            var supplier = this.GetLastPeriodDebtOfSupplier(supplierId, DateTime.Now);            
            if (supplier != null && supplier.Debt.Equals(debt))
            {
                return;
            }
            var newObj = new BoughtMerchandiseDebit()
            {
                Id = Guid.NewGuid(),
                Debt = debt,
                FromDate = DateTime.Now,
                SupplierId = supplierId,
            };
            Context.BoughtMerchandiseDebits.InsertOnSubmit(newObj);
        }
        public void UpdateAllSupplierDebts(IEnumerable<SupplierAndDebtDTO> updatedList)
        {
            try
            {
                this.BeginTransaction();
                foreach (var item in updatedList)
                {
                    UpdateSupplierDebt(item.SupplierId, item.Debt);
                }
                this.SubmitChanges();
                this.CommitTransaction();
            }
            catch (Exception ex)
            {
                this.RollbackTransaction();
                throw ex;
            }
        }
    }
}
